#include <iostream>
#include <thread>
#include <unistd.h>
#include <string>
#include <cassert>

using namespace std;


int tickets =1000 ; 


//修改线程数量，观察线程数量对抢票时间的影响
#define THREAD_NUM 10   


class ThreadData
{
public:

    ThreadData(const string & n , pthread_mutex_t *pm)
        :_tname(n)
        ,_pmtx(pm)
    {}
public:

    string _tname ;
    pthread_mutex_t* _pmtx ;
};


void* getTicketes(void* args)
{
    ThreadData* td = (ThreadData*)args;

    while(true)
    {
        int n = pthread_mutex_lock(td->_pmtx);
        assert(n == 0);

        //临界区 
        //比较是逻辑运算，也是计算。是计算就有可能受线程中断影响
        printf("debug3\n");

        if(tickets > 0 )
        {
            usleep(rand() % 10);
            printf("%s : %d \n", td->_tname.c_str(),tickets) ;
            tickets-- ; 

            n =pthread_mutex_unlock(td->_pmtx);
            assert(n == 0 );
        }
        else
        {
            n = pthread_mutex_unlock(td->_pmtx);
            assert(n == 0);
            break ;
        }
    }

    delete td ;
    return nullptr;
}


int main()
{

    //printf("debug0\n");

    time_t strart = time(nullptr); //用于计时执行时间

    pthread_mutex_t mtx; //pthread_mutex_t是需要被初始化的互斥量
    
    pthread_mutex_init(&mtx,nullptr); 

    pthread_t t[THREAD_NUM] ; //用来接受线程id

    //printf("debug1\n");

    for(int i = 0 ; i < THREAD_NUM ; i++)
    {

        //printf("debug2\n");

        string name = "thread" ;
        name = name + "---" +  to_string(i+1);
        ThreadData *td = new ThreadData(name, &mtx);
        pthread_create(t + i, nullptr , getTicketes,(void*)td);
    }

    for(int i = 0 ; i < THREAD_NUM ; i++)
    {
        pthread_join(t[i],nullptr);
    }

    time_t end = time(nullptr);

    pthread_mutex_destroy(&mtx);

    cout << "抢票用时 :"<< (int)(end - strart) << "s"<< endl ; 
    
    return 0 ;
}
